#include <sdl/sdl.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#include <SDL_gfxPrimitives.h>
#include <chunks/GuacImage_draw_setup.h>
#include "guacimage.h"

static int raw_draw_image(lua_State *L)
{
    GuacImage* dst = (GuacImage*)lua_touserdata(L,1);
    GuacImage* src = (GuacImage*)lua_touserdata(L,2);
    if (dst->flags & IMG_FLAG_LOCKED)
        return luaL_error(L, "attempt to modify read-only image");
    SDL_SetClipRect(dst->surf, dst->prect);
    SDL_Rect dstrect = {luaL_optint(L,3,0) - src->handle_x, luaL_optint(L,4,0) - src->handle_y, 0, 0};
    SDL_BlitSurface(src->surf, src->prect, dst->surf, &dstrect);
    return 0;
}

static int raw_draw_line(lua_State *L)
{
    GuacImage* img = (GuacImage*)lua_touserdata(L,1);
    if (img->flags & IMG_FLAG_LOCKED)
        return luaL_error(L, "attempt to modify read-only image");
    switch(lua_gettop(L))
    {
        case 6:
            SDL_SetClipRect(img->surf, img->prect);
            if (img->prect)
            {
                lineColor(img->surf,
                    img->prect->x + luaL_checkint(L,2),img->prect->y + luaL_checkint(L,3),
                    img->prect->x + luaL_checkint(L,4),img->prect->y + luaL_checkint(L,5),
                    luaL_checkint(L,6)
                );
            }
            else
            {
                lineColor(img->surf,
                    luaL_checkint(L,2),luaL_checkint(L,3),
                    luaL_checkint(L,4),luaL_checkint(L,5),
                    luaL_checkint(L,6)
                );
            }
            return 0;
        case 8:
            SDL_SetClipRect(img->surf, img->prect);
            if (img->prect)
            {
                lineRGBA(img->surf,
                    img->prect->x + luaL_checkint(L,2),img->prect->y + luaL_checkint(L,3),
                    img->prect->x + luaL_checkint(L,4),img->prect->y + luaL_checkint(L,5),
                    luaL_checkint(L,6),luaL_checkint(L,7),luaL_checkint(L,8),255
                );
            }
            else
            {
                lineRGBA(img->surf,
                    luaL_checkint(L,2),luaL_checkint(L,3),
                    luaL_checkint(L,4),luaL_checkint(L,5),
                    luaL_checkint(L,6),luaL_checkint(L,7),luaL_checkint(L,8),255
                );
            }
            return 0;
        case 9:
            SDL_SetClipRect(img->surf, img->prect);
            if (img->prect)
            {
                lineRGBA(img->surf,
                    img->prect->x + luaL_checkint(L,2),img->prect->y + luaL_checkint(L,3),
                    img->prect->x + luaL_checkint(L,4),img->prect->y + luaL_checkint(L,5),
                    luaL_checkint(L,6),luaL_checkint(L,7),luaL_checkint(L,8),luaL_checkint(L,9)
                );
            }
            else
            {
                lineRGBA(img->surf,
                    luaL_checkint(L,2),luaL_checkint(L,3),
                    luaL_checkint(L,4),luaL_checkint(L,5),
                    luaL_checkint(L,6),luaL_checkint(L,7),luaL_checkint(L,8),luaL_checkint(L,9)
                );
            }
            return 0;
        default:
            return luaL_error(L, "unexpected number of arguments");
    }
}

static int raw_draw_pixel(lua_State *L)
{
    GuacImage* img = (GuacImage*)lua_touserdata(L,1);
    if (img->flags & IMG_FLAG_LOCKED)
        return luaL_error(L, "attempt to modify read-only image");
    switch(lua_gettop(L))
    {
        case 4:
            SDL_SetClipRect(img->surf, img->prect);
            if (img->prect)
            {
                pixelColor(img->surf,
                    img->prect->x + luaL_checkint(L,2),img->prect->y + luaL_checkint(L,3),
                    luaL_checkint(L,4)
                );
            }
            else
            {
                pixelColor(img->surf,
                    luaL_checkint(L,2),luaL_checkint(L,3),
                    luaL_checkint(L,4)
                );
            }
            return 0;
        case 6:
            SDL_SetClipRect(img->surf, img->prect);
            if (img->prect)
            {
                pixelRGBA(img->surf,
                    img->prect->x + luaL_checkint(L,2),img->prect->y + luaL_checkint(L,3),
                    luaL_checkint(L,4),luaL_checkint(L,5),luaL_checkint(L,6),255
                );
            }
            else
            {
                pixelRGBA(img->surf,
                    luaL_checkint(L,2),luaL_checkint(L,3),
                    luaL_checkint(L,4),luaL_checkint(L,5),luaL_checkint(L,6),255
                );
            }
            return 0;
        case 7:
            SDL_SetClipRect(img->surf, img->prect);
            if (img->prect)
            {
                pixelRGBA(img->surf,
                    img->prect->x + luaL_checkint(L,2),img->prect->y + luaL_checkint(L,3),
                    luaL_checkint(L,4),luaL_checkint(L,5),luaL_checkint(L,6),luaL_checkint(L,7)
                );
            }
            else
            {
                pixelRGBA(img->surf,
                    luaL_checkint(L,2),luaL_checkint(L,3),
                    luaL_checkint(L,4),luaL_checkint(L,5),luaL_checkint(L,6),luaL_checkint(L,7)
                );
            }
            return 0;
        default:
            return luaL_error(L, "unexpected number of arguments");
    }
}

static int raw_draw_box(lua_State *L)
{
    GuacImage* img = (GuacImage*)lua_touserdata(L,1);
    if (img->flags & IMG_FLAG_LOCKED)
        return luaL_error(L, "attempt to modify read-only image");
    switch(lua_gettop(L))
    {
        case 6:
            SDL_SetClipRect(img->surf, img->prect);
            if (img->prect)
            {
                boxColor(img->surf,
                    img->prect->x + luaL_checkint(L,2),img->prect->y + luaL_checkint(L,3),
                    luaL_checkint(L,4),luaL_checkint(L,5),
                    luaL_checkint(L,6)
                );
            }
            else
            {
                boxColor(img->surf,
                    luaL_checkint(L,2),luaL_checkint(L,3),
                    luaL_checkint(L,4),luaL_checkint(L,5),
                    luaL_checkint(L,6)
                );
            }
            return 0;
        case 8:
            SDL_SetClipRect(img->surf, img->prect);
            if (img->prect)
            {
                boxRGBA(img->surf,
                    img->prect->x + luaL_checkint(L,2),img->prect->y + luaL_checkint(L,3),
                    luaL_checkint(L,4),luaL_checkint(L,5),
                    luaL_checkint(L,6),luaL_checkint(L,7),luaL_checkint(L,8),255
                );
            }
            else
            {
                boxRGBA(img->surf,
                    luaL_checkint(L,2),luaL_checkint(L,3),
                    luaL_checkint(L,4),luaL_checkint(L,5),
                    luaL_checkint(L,6),luaL_checkint(L,7),luaL_checkint(L,8),255
                );
            }
            return 0;
        case 9:
            SDL_SetClipRect(img->surf, img->prect);
            if (img->prect)
            {
                boxRGBA(img->surf,
                    img->prect->x + luaL_checkint(L,2),img->prect->y + luaL_checkint(L,3),
                    luaL_checkint(L,4),luaL_checkint(L,5),
                    luaL_checkint(L,6),luaL_checkint(L,7),luaL_checkint(L,8),luaL_checkint(L,9)
                );
            }
            else
            {
                boxRGBA(img->surf,
                    luaL_checkint(L,2),luaL_checkint(L,3),
                    luaL_checkint(L,4),luaL_checkint(L,5),
                    luaL_checkint(L,6),luaL_checkint(L,7),luaL_checkint(L,8),luaL_checkint(L,9)
                );
            }
            return 0;
        default:
            return luaL_error(L, "unexpected number of arguments");
    }
}

static luaL_Reg raw_draw_funcs[] = {
    {"image",raw_draw_image},
    {"line",raw_draw_line},
    {"pixel",raw_draw_pixel},
    {"box",raw_draw_box},
    {NULL,NULL}
};

int luaopen_draw(lua_State *L)
{
    lua_newtable(L);
    luaL_register(L, NULL, raw_draw_funcs);
    luaL_loadbuffer(L, chunk_GuacImage_draw_setup, sizeof(chunk_GuacImage_draw_setup), NULL);
    lua_insert(L,-2);
    lua_call(L,1,1);

    lua_pushvalue(L,-1);
    lua_setglobal(L, "draw");

    return 1;
}
